﻿//
// Created by 17616 on 2021/3/20.
//

#ifndef TIFFREADER_PUBLIC_H
#define TIFFREADER_PUBLIC_H
#include <string>
#include <vector>
#include <sstream>
#include <opencv2/opencv.hpp>
#include <thread>
#include <functional>


//替换字符串
std::string &replace_str(std::string &str, const std::string &to_replaced, const std::string &newchars);


//计算文件名中的曝光时间，单位为us
double GetTimer(std::string name);

//格式化字符串
std::string Format(const char *fmt, ...);

//计算浮点图对应曝光时间的u8图,曝光时间单位为us
void Calculate_u8(const cv::Mat &src, cv::Mat &dst, float expTime);

template<bool log_flag = true>
bool MyOtsu(const cv::Mat src, cv::Mat dst, bool view_mode) {
//    针对浮点图像的otsu
    //统计原图的最大值最小值
    float max_v = 0;
    float min_v = FLT_MAX;
    for (int r = 0; r < src.rows; ++r) {
        float *pix_src = (float *) ((size_t) src.data + r * src.step);
        for (int c = 0; c < src.cols; ++c) {
            if (*pix_src > max_v) {
                max_v = *pix_src;
            }
            if (*pix_src < min_v) {
                min_v = *pix_src;
            }
            pix_src++;
        }
    }
    int N = 0;
    std::vector<float> g;//类间方差
    std::vector<float> t;//直方图间隔
    float scale = exp(log(max_v / min_v) / 256);
    //这里从2开始是为了屏蔽太小的
    for (float i = 2 * min_v; i <= max_v; i *= scale) {
        g.push_back(0);
        t.push_back(i);
        N += 1;
    }
    auto paralfunc = [&](int s, int e) {
        float w0, u0, w1, u1;
        float u;//平均总灰度
        for (int i = s; i < e; ++i) {
            //遍历图像总平均灰度
            u = 0;
            for (int r = 0; r < src.rows; ++r) {
                float *pix_src = (float *) ((size_t) src.data + r * src.step);
                for (int c = 0; c < src.cols; ++c) {
                    if constexpr (log_flag) {
                        u += log(*pix_src);
                    } else {
                        u += *pix_src;
                    }
                    pix_src++;
                }
            }
            u /= (src.rows * src.cols);

            //计算权值函数
            w0 = 0;//比例
            u0 = 0;//均值
            w1 = 0;
            u1 = 0;
            for (int r = 0; r < src.rows; ++r) {
                float *pix_src = (float *) ((size_t) src.data + r * src.step);
                for (int c = 0; c < src.cols; ++c) {
                    if (*pix_src < t[i]) {
                        w0 += 1;
                        if constexpr(log_flag) {
                            u0 += log(*pix_src);
                        } else {
                            u0 += *pix_src;
                        }
                    } else {
                        w1 += 1;
                        if constexpr (log_flag) {
                            u1 += log(*pix_src);
                        } else {
                            u1 += *pix_src;
                        }
                    }
                    pix_src++;
                }
            }
            u0 = w0 == 0 ? 0 : u0 / w0;
            u1 = w1 == 0 ? 0 : u1 / w1;
            w0 /= (src.rows * src.cols);
            w1 /= (src.rows * src.cols);
            g[i] = w0 * (u0 - u) * (u0 - u) + w1 * (u1 - u) * (u1 - u);
        }
    };

    thread_pool *tp = new thread_pool(0, N);
    tp->post(paralfunc);
    tp->join();
    delete tp;
//    paralfunc(0, N);
    float threshold = min_v;
    float max_g = 0;
    for (int i = 0; i < N; ++i) {
        if (g[i] > max_g) {
            max_g = g[i];
            threshold = t[i];
        }
    }
    auto g_flag = true;
    for (int i = 0; i < N - 1; ++i) {
        if (g[i] < g[i + 1]) {
            g_flag = false;
        }
    }
    if (g_flag) {
        printf("权值阶梯递减\r\n");
        return false;
    }
    for (int i = 0; i < N; ++i) {
        if (g[i] > max_g) {
            max_g = g[i];
            threshold = t[i];
        }
    }

    int count = 0;
    if (!view_mode) {
        for (int r = 0; r < src.rows; ++r) {
            float *pix_src = (float *) ((size_t) src.data + r * src.step);
            uchar *pix_dst = (uchar *) ((size_t) dst.data + r * dst.step);
            for (int c = 0; c < src.cols; ++c) {
                if (*pix_src > threshold) {
                    *pix_dst = 255;
                    count++;
                } else {
                    *pix_dst = 0;
                }
                pix_dst++;
                pix_src++;
            }
        }
    } else {
        for (int r = 0; r < src.rows; ++r) {
            float *pix_src = (float *) ((size_t) src.data + r * src.step);
            uchar *pix_dst = (uchar *) ((size_t) dst.data + r * dst.step);
            for (int c = 0; c < src.cols; ++c) {
                if (*pix_src > threshold) {
                    *pix_dst ^= 255;
                    count++;
                } else {
                }
                pix_dst++;
                pix_src++;
            }
        }
    }
    return count < 0.9 * src.rows * src.cols;

}


//获取文件路径，带最后的‘/’
std::string GetFilePath(std::string file);
std::string GetFileName(std::string file);
std::string GetFilePathWithoutType(std::string file);


extern double WTable[256]; //权重查找表
extern double LogTable[256]; //Log函数查找表

// 并行计算线程类，和标准库的thread_pool不是同一个东西
class thread_pool {
public:
    thread_pool(int start, int end, int concurrency_ = std::thread::hardware_concurrency());
    void post(std::function<void(int, int)> task_to_run);
    void join();
private:
    bool did;
    std::vector<std::thread> threads;
    std::vector<int> points;
    int concurrency;
};

// 用于辅助在函数退出时候能及时释放资源，替代"goto :exit"
class destructHelper {
    std::vector<std::function<void(void)> > destructs;
public:
    destructHelper() {}
    destructHelper(std::function<void(void)> f) {
        destructs.push_back(f);
    }
    ~destructHelper() {
        for (auto &f:destructs) {
            f();
        }
    }
    void push_back(std::function<void(void)> f) {
        destructs.push_back(f);
    }
};

#endif //TIFFREADER_PUBLIC_H
